﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace SearchInterface
{
    public partial class Window : Form, Callback
    {
        private delegate void AddSearchDelegate(int searchid, hydrap2p.search.SearchQuery query, List<String> providers);
        private delegate void AddSearchResultDelegate(int searchid, hydrap2p.search.SearchResult result);
        private delegate void SearchIDDelegate(int searchid);
        private delegate void SearchIDStringDelegate(int searchid, String temp);

        private Dictionary<int, TabPage> tabs;
        private Dictionary<int, TreeView> resultlists;
        private Dictionary<int, Dictionary<int, TreeNode>> resultnodes;
        private Dictionary<int, Dictionary<int, hydrap2p.search.SearchResult>> results;
        private Dictionary<int, List<String>> activeproviders;
        private Dictionary<int, Button> deletebuttons;
        private Dictionary<int, Label> providerlabels;
        private Controller controller;

        private const int LISTPADDING = 20;

        public Window()
        {
            InitializeComponent();
            tabs=new Dictionary<int,TabPage>();
            resultlists=new Dictionary<int, TreeView>();
            resultnodes = new Dictionary<int, Dictionary<int, TreeNode>>();
            results = new Dictionary<int, Dictionary<int, hydrap2p.search.SearchResult>>();
            deletebuttons = new Dictionary<int,Button>();
            providerlabels = new Dictionary<int, Label>();
            activeproviders = new Dictionary<int, List<string>>();

            try
            {
                controller = new Controller(this);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
                throw e;
            }
            btnReloadSeachers_Click(null, null);
        }

        #region Callback Members

        public void error(string error)
        {
            MessageBox.Show("An error occurred: " + error);
        }

        public void addSearch(int searchid, hydrap2p.search.SearchQuery query, List<String> providers)
        {
            if (InvokeRequired)
            {
                // We're not in the UI thread, so we need to call BeginInvoke
                BeginInvoke(new AddSearchDelegate(addSearch), new object[] { searchid, query, providers });
                return;
            }
            // Must be on the UI thread if we've got this far

            Dictionary<int, hydrap2p.search.SearchResult> thisresults = new Dictionary<int, hydrap2p.search.SearchResult>();
            Dictionary<int, TreeNode> thisnodes = new Dictionary<int, TreeNode>();
            

            TabPage temp=new TabPage(query.Name);
            TreeView templist = new TreeView();
            templist.Left = LISTPADDING;
            templist.Top = LISTPADDING;
            templist.Width = tabSearches.TabPages[0].Width - 2 * LISTPADDING;
            templist.Height = tabSearches.TabPages[0].Height - 2 * LISTPADDING;
            templist.CheckBoxes = true;
            templist.BeforeCheck+=new TreeViewCancelEventHandler(listChecked);
            

            try
            {
                //templist.DataSource = thisresults;
                //templist.DisplayMember = "Value";

                temp.Controls.Add(templist);
                tabSearches.TabPages.Add(temp);
                tabSearches.SelectTab(temp);

                Button deletebutton = new Button();
                deletebutton.Text = "Remove";
                deletebutton.Left = templist.Left + templist.Width - deletebutton.Width;
                deletebutton.Click += new EventHandler(deletebutton_Click);
                deletebuttons[searchid] = deletebutton;
                temp.Controls.Add(deletebutton);

                Label providerlabel = new Label();
                providerlabel.Text = "Searching " + String.Join(", ", providers.ToArray());
                providerlabel.Left = LISTPADDING;
                providerlabel.Top = templist.Top + templist.Height;
                providerlabel.Width = templist.Width;
                providerlabels[searchid] = providerlabel;
                temp.Controls.Add(providerlabel);

                // add organization stuff in the background
                resultlists.Add(searchid, templist);
                tabs.Add(searchid, temp);
                results.Add(searchid, thisresults);
                resultnodes.Add(searchid, thisnodes);
                activeproviders.Add(searchid, providers);

            }
            catch (Exception e)
            {
                System.Console.WriteLine(e.Message);
            }
        }

        void deletebutton_Click(object sender, EventArgs e)
        {
            foreach (KeyValuePair<int, Button> button in deletebuttons)
            {
                if (button.Value == sender)
                    controller.deleteSearch(button.Key);
            }
        }

        public void delSearch(int searchid)
        {
            if (InvokeRequired)
            {
                // We're not in the UI thread, so we need to call BeginInvoke
                BeginInvoke(new SearchIDDelegate(delSearch), new object[] { searchid });
                return;
            }
            // Must be on the UI thread if we've got this far

            if (tabs.ContainsKey(searchid))
            {
                tabSearches.TabPages.Remove(tabs[searchid]);
                resultlists.Remove(searchid);
                resultnodes.Remove(searchid);
                results.Remove(searchid);
                tabs.Remove(searchid);
                deletebuttons.Remove(searchid);
                providerlabels.Remove(searchid);
                activeproviders.Remove(searchid);
            }
        }

        public void addSearchResult(int searchid, hydrap2p.search.SearchResult result)
        {
            if (InvokeRequired)
            {
                // We're not in the UI thread, so we need to call BeginInvoke
                BeginInvoke(new AddSearchResultDelegate(addSearchResult), new object[] { searchid, result });
                return;
            }
            // Must be on the UI thread if we've got this far

            if (resultlists.ContainsKey(searchid))
            {
                try
                {
                    String text = result.Provider + ": " + result.Filenames[0] + " "+result.Sources.Count+" sources";
                    if (!results[searchid].ContainsKey(result.Resultid))
                    {
                        TreeNode newnode = new TreeNode(text);
                        resultlists[searchid].Nodes.Add(newnode);
                        resultnodes[searchid][result.Resultid] = newnode;
                    }
                    results[searchid][result.Resultid] = result;
                    TreeNode parentnode = resultnodes[searchid][result.Resultid];
                    parentnode.Nodes.Clear();
                    foreach (hydrap2p.download.Source source in result.Sources)
                    {
                        parentnode.Nodes.Add(source.Protocol + " - " + source.Ip + ":" + source.Port);
                    }
                }
                catch (Exception e)
                {
                    System.Console.WriteLine(e.Message);
                }
            }
        }

        public void searchFinished(int searchid)
        {
            if (InvokeRequired)
            {
                // We're not in the UI thread, so we need to call BeginInvoke
                BeginInvoke(new SearchIDDelegate(searchFinished), new object[] { searchid });
                return;
            }
            // Must be on the UI thread if we've got this far

            if (activeproviders.ContainsKey(searchid))
                activeproviders[searchid].Clear();
            if (providerlabels.ContainsKey(searchid))
                providerlabels[searchid].Text = "Done";
        }

        public void searchProviderFinished(int searchid, string providername)
        {
            if (InvokeRequired)
            {
                // We're not in the UI thread, so we need to call BeginInvoke
                BeginInvoke(new SearchIDStringDelegate(searchProviderFinished), new object[] { searchid, providername });
                return;
            }
            // Must be on the UI thread if we've got this far

            if (providerlabels.ContainsKey(searchid) && activeproviders.ContainsKey(searchid) && activeproviders[searchid].Contains(providername))
            {
                activeproviders[searchid].Remove(providername);
                providerlabels[searchid].Text = "Searching " + String.Join(", ", activeproviders[searchid].ToArray());
            }
        }

        #endregion

        private void btnSearch_Click(object sender, EventArgs e)
        {
            controller.startSearch(txtKeywords.Text);
        }

        private void btnReloadSeachers_Click(object sender, EventArgs e)
        {
            List<String> searchers=controller.getSearchers();
            treSearchers.Nodes.Clear();
            foreach (String searcher in searchers)
                treSearchers.Nodes.Add(searcher);

        }

        private void listChecked(object sender, TreeViewCancelEventArgs e)
        {
            foreach (KeyValuePair<int, TreeView> result in resultlists)
            {
                if (result.Value == sender)
                {
                    foreach (KeyValuePair<int, TreeNode> node in resultnodes[result.Key])
                    {
                        if (e.Node == node.Value)
                            controller.download(results[result.Key][node.Key].Names[0], result.Key, node.Key);
                    }
                }
            }
        }
    }
}
